// A BrianVM challenge solution for Win32
//
// This implementation talks directly to Win32 and does not require a C
// runtime. It compiles to just a few kB (mostly padding) and works with both
// Mingw-w64 and MSVC. This program helped dogfood w64devkit.
//
// Mingw-w64:
//   $ cc -Os -s -nostdlib brianvm.c -lkernel32 -ladvapi32
//
// MSVC:
//   $ cl /Os /GS- brianvm.c /link /nodefaultlib /subsystem:console
//        kernel32.lib advapi32.lib
//
// This is free and unencumbered software released into the public domain.
#include <windows.h>
#include <ntsecapi.h>

int
mainCRTStartup(void)
{
    DWORD u;
    HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
    GetConsoleMode(h, &u);
    SetConsoleMode(h, u|ENABLE_VIRTUAL_TERMINAL_PROCESSING);

    unsigned char m[256] = {
        0x01,0x04,0x07,0x0a,0x00,0x0d,0x00,0xf8,0x02,0x07,0x01,0x09,0x00,0x04,
        0x07,0x00,0x02,0x07,0xf8,0x07,0xe0,0x06,0xe0,0x3a,0x07,0xdf,0x06,0xdf,
        0x18,0x01,0xff,0xdf,0x06,0xff,0x0a,0x02,0xff,0x30,0x01,0xd9,0xff,0x05,
        0xdf,0x0a,0x02,0xdf,0x30,0x01,0xd8,0xdf,0x01,0xff,0xe0,0x06,0xff,0x0a,
        0x02,0xff,0x30,0x01,0xdc,0xff,0x05,0xe0,0x0a,0x02,0xe0,0x30,0x01,0xdb,
        0xe0,0x01,0x4b,0x4e,0x0a,0x00,0x54,0x00,0xd6,0x02,0x4e,0x01,0x09,0x47,
        0x04,0x4e,0x00,0x02,0x4e,0xd6,0x07,0xff,0x06,0xff,0x08,0x02,0xff,0x30,
        0x01,0xd1,0xff,0x01,0x69,0x6c,0x0a,0x00,0x72,0x00,0xce,0x02,0x6c,0x01,
        0x09,0x65,0x04,0x6c,0x00,0x02,0x6c,0xce,0x01,0x7c,0x7f,0x0a,0x00,0x87,
        0x00,0xe1,0x02,0x7f,0x01,0x08,0x8c,0x09,0x78,0x04,0x7f,0x00,0x02,0x7f,
        0xe1,0x08,0xfa,0x08,0xfa,0x09,0x13,0x6a,0xba,0x1f,0x6d,0xa3,0xe6,0xad,
        0x3b,0xae,0x4d,0x6e,0xc1,0xfa,0x11,0xed,0x22,0x2e,0x6d,0xa3,0xed,0x48,
        0x3d,0xf9,0x4d,0xed,0x24,0x29,0x2a,0x16,0xe3,0x09,0x25,0xc6,0x31,0x62,
        0xb5,0x21,0x2e,0xa0,0x47,0x5b,0xa2,0x02,0x3c,0x82,0x83,0x4f,0x58,0x2a,
        0x65,0x87,0x25,0x43,0x6d,0xde,0xa9,0x31,0x81,0x09,0x1b,0x5b,0x39,0x63,
        0x3b,0x31,0x6d,0x00,0x1b,0x5b,0x78,0x78,0x3b,0x79,0x79,0x48,0x00,0x18,
        0x55,0x47,0x65,0x74,0x20,0x77,0x65,0x6c,0x6c,0x20,0x73,0x6f,0x6f,0x6e,
        0x2c,0x20,0x42,0x72,0x69,0x61,0x6e,0x21,0x0a,0x00,0x1b,0x5b,0x32,0x4a,
        0x1b,0x5b,0x48,0x00
    };

    for (int pc = 0;;) {
        switch (m[pc++]) {
        case  0: WriteFile(h, &m[m[pc++]], 1, &u, 0); break;
        case  1: m[m[pc]]  = m[m[pc+1]]; pc += 2;     break;
        case  2: m[m[pc]] += m[pc+1];    pc += 2;     break;
        case  3: m[m[pc]] -= m[pc+1];    pc += 2;     break;
        case  4: m[m[pc]] *= m[pc+1];    pc += 2;     break;
        case  5: m[m[pc]] /= m[pc+1];    pc += 2;     break;
        case  6: m[m[pc]] %= m[pc+1];    pc += 2;     break;
        case  7: RtlGenRandom(&m[m[pc++]], 1);        break;
        case  8: Sleep(m[pc++]);                      break;
        case  9: pc = m[pc];                          break;
        case 10: pc = !m[m[pc]] ? m[pc+1] : pc + 2;   break;
        }
    }
}
